name: Build Release

on:
  # Manual Trigger GH CLI -> gh workflow run release.yml --ref <tag>
  workflow_dispatch:

jobs:
  run-python-tests:
    uses: ./.github/workflows/python-versions.yml
    with:
      ref: ${{ github.ref_name }}
    secrets:
      PARAMETER_PASSWORD: ${{ secrets.PARAMETER_PASSWORD }}
    permissions:
      # Permission needed to upload constraints file
      contents: write

  run-javascript-tests:
    uses: ./.github/workflows/js-tests.yml
    with:
      ref: ${{ github.ref_name }}

  run-py-prod-deps-smoke-test:
    uses: ./.github/workflows/py-prod-deps-smoke-test.yml
    with:
      ref: ${{ github.ref_name }}

  run-cypress-tests:
    uses: ./.github/workflows/cypress.yml
    with:
      ref: ${{ github.ref_name }}

  run-playwright-tests:
    uses: ./.github/workflows/playwright.yml
    with:
      ref: ${{ github.ref_name }}

  build-release:
    runs-on: ubuntu-latest

    needs:
      - run-python-tests
      - run-javascript-tests
      - run-py-prod-deps-smoke-test
      - run-cypress-tests
      - run-playwright-tests

    defaults:
      run:
        shell: bash --login -eo pipefail {0}

    permissions:
      # Additional permission needed to generate release
      contents: write

    env:
      # Name of the tag
      GIT_TAG: ${{ github.ref_name }}
      # The owner and repository name
      GH_REPO: ${{ github.repository }}
      # A branch with constraints files on the basis of which
      # the tag will be created.
      CONSTRAINTS_BRANCH: constraints-release
      # The name of the tag that contains the constraints files
      # for the current release
      CONSTRAINTS_TAG: constraints/${{ github.ref_name }}
      # We don't want to use constraints files because they might not exist yet.
      USE_CONSTRAINTS_FILE: "false"

    steps:
      - name: Checkout Streamlit code
        uses: actions/checkout@v4
        with:
          ref: ${{ github.ref_name }}
          # Save the access token to the local git config, so
          # later git commands can work.
          persist-credentials: true
          submodules: "recursive"
          fetch-depth: 2
      - name: Set Python version vars
        uses: ./.github/actions/build_info
      - name: Set up Python ${{ env.PYTHON_MAX_VERSION }}
        uses: actions/setup-python@v5
        with:
          python-version: "${{ env.PYTHON_MAX_VERSION }}"
      - name: Look up the related GitHub PR branch name
        # Need GH Token to use gh api
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          pip install requests
          echo "GH_PR_BRANCH=$(python scripts/get_release_branch.py)" >> $GITHUB_ENV
      - name: Ensure release branch corresponding to this tag exists
        env:
          GH_PR_BRANCH: ${{ env.GH_PR_BRANCH }}
        run: |
          BRANCH_VERSION=$(echo "$GH_PR_BRANCH" | sed 's/release\///' )
          if [ "$BRANCH_VERSION" != "$GIT_TAG" ]
          then
            echo "ERROR: release branch corresponding to this tag does not exist."
            exit 1
          fi
      - name: Setup virtual env
        uses: ./.github/actions/make_init
      - name: Set release version from tag name
        env:
          GIT_TAG: ${{ env.GIT_TAG }}
        run: echo "STREAMLIT_RELEASE_VERSION=$GIT_TAG" >> $GITHUB_ENV
      - name: Create Package
        timeout-minutes: 120
        run: |
          sudo apt install rsync
          make package
      - name: Store Package
        uses: actions/upload-artifact@v3
        with:
          name: Release
          path: lib/dist
      - name: Upload to PyPI
        env:
          TWINE_USERNAME: ${{ secrets.STREAMLIT_PYPI_USERNAME }}
          TWINE_PASSWORD: ${{ secrets.STREAMLIT_PYPI_API_TOKEN }}
        run: |
          make distribute
      - name: Create GitHub Release
        env:
          GIT_TAG: ${{ env.GIT_TAG }}
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          python scripts/create_release.py

      - name: Checkout branch "${{ env.CONSTRAINTS_BRANCH }}"
        uses: actions/checkout@v4
        with:
          ref: ${{ env.CONSTRAINTS_BRANCH }}
          # Save the access token to the local git config, so
          # later git commands can work.
          persist-credentials: true
          path: constraints
      - uses: actions/download-artifact@v3
        with:
          name: constraints
          path: constraints
      - name: Commit and push constraint files as tag
        run: |
          cd constraints;
          git add .
          git config --local user.email "core+streamlitbot-github@streamlit.io"
          git config --local user.name "Streamlit Bot"
          if ! git diff --cached --color --exit-code --ignore-matching-lines="^#.*"
          then
            git commit --all --message "Updating constraints. Github run id:${GITHUB_RUN_ID}

            This update in constraints is automatically committed by the CI based on
            '${GITHUB_REF}' in the '${GITHUB_REPOSITORY}' repository with commit sha ${GITHUB_SHA}.

            The action that build those constraints can be found at https://github.com/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}/
            "
          else
            echo "No changes"
          fi
          git tag "${CONSTRAINTS_TAG}"
          git push origin "${CONSTRAINTS_TAG}";
          git push origin "${CONSTRAINTS_BRANCH}";

      - name: Successful Release Slack Message
        if: ${{ success() }}
        env:
          SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
          RUN_ID: ${{ github.run_id }}
        run: python scripts/slack_notifications.py release success
      - name: Failed Release Slack Message
        if: ${{ failure() }}
        env:
          SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
          RUN_ID: ${{ github.run_id }}
        run: python scripts/slack_notifications.py release failure
